#include "EditorSplitableLayoutViewModel.h"
#include "EditorSplitableLayoutModel.h"
#include "Misc/Assert.h"


void REditorSplitableLayoutViewModel::BindModel(TSharedObjectPtr<REditorSplitableLayoutModel> InModel)
{
    Model = InModel;

    //创建视图模型
    GASSERTEXP(OnBindItemViewModel.IsBound());
    ItemModels.Resize(Model->Nodes.Num());
    ItemViewModels.Resize(Model->Nodes.Num());
    for (int64_t i = 0; i < Model->Nodes.Num(); i++)
    {
        auto Node = Model->Nodes[i];
        if(!Node->IsA<REditorSplitableLayoutLeafNode>())
        {
            ItemModels[i]=nullptr;
            ItemViewModels[i]=nullptr;
            continue;
        }
        REditorSplitableLayoutLeafNodePtr LeafNode = Node;
        ItemModels[i] = LeafNode->ItemWidgetModel;
        ItemViewModels[i] = OnBindItemViewModel.Broadcast(LeafNode->ItemWidgetModel);
        GASSERTEXP(ItemViewModels[i]);
        
    }


    Model->OnLayoutChanged.Bind(
        [this]()
        {
            auto OldItemViewModels = ItemViewModels;
            auto OldItemModels = ItemModels;

            ItemModels.Resize(Model->Nodes.Num());
            ItemViewModels.Resize(Model->Nodes.Num());
            for (int64_t i = 0; i < Model->Nodes.Num(); i++)
            {
                auto Node = Model->Nodes[i];
                if (!Node->IsA<REditorSplitableLayoutLeafNode>())
                {
                    ItemModels[i] = nullptr;
                    ItemViewModels[i] = nullptr;
                    continue;
                }

                REditorSplitableLayoutLeafNodePtr LeafNode = Node;
                //如果之前已经有了，就不再创建
                auto FoundIndex = ItemModels.Find(LeafNode->ItemWidgetModel);
                if (FoundIndex.HasValue())
                {
                    ItemModels[i] = LeafNode->ItemWidgetModel;
                    ItemViewModels[i] = OldItemViewModels[FoundIndex.GetValue()];
                }
                else
                {
                    ItemModels[i] = LeafNode->ItemWidgetModel;
                    ItemViewModels[i] = OnBindItemViewModel.Broadcast(LeafNode->ItemWidgetModel);
                }

                GASSERTEXP(ItemViewModels[i]);
                
            }

            OnLayoutChanged.ExecuteIfBound();
        }
    );

}
int64_t REditorSplitableLayoutViewModel::GetNodeNum() const
{
    return Model->Nodes.Num();
}

int64_t REditorSplitableLayoutViewModel::GetNodeSpliterNum(int64_t NodeIndex) const
{
    auto Node = Model->Nodes[NodeIndex];
    if (Node->IsA<REditorContainerSplitableLayoutNode>())
    {
        REditorContainerSplitableLayoutNodePtr ContainerNode = Node;
        return ContainerNode->Children.Num() - 1;
    }
    return 0;
}

bool REditorSplitableLayoutViewModel::HasSubNode(int64_t NodeIndex) const
{
    auto Node = Model->Nodes[NodeIndex];
    return Node->IsA<REditorContainerSplitableLayoutNode>();
}

TVector<int64_t> REditorSplitableLayoutViewModel::GetSubNodeIndices(int64_t NodeIndex) const
{
    return Model->SubNodeIndices[NodeIndex];
}

float REditorSplitableLayoutViewModel::GetSubNodeSize(int64_t NodeIndex, int64_t SubNodeIndex) const
{
    auto Node = Model->Nodes[NodeIndex];
    if (Node->IsA<REditorContainerSplitableLayoutNode>())
    {
        REditorContainerSplitableLayoutNodePtr ContainerNode = Node;
        return ContainerNode->GetSubNodeSize(SubNodeIndex);
    }
    return 0;
}

void REditorSplitableLayoutViewModel::SetSubNodeSize(int64_t NodeIndex, int64_t SubNodeIndex, float Size)
{
    auto Node = Model->Nodes[NodeIndex];
    if (Node->IsA<REditorContainerSplitableLayoutNode>())
    {
        REditorContainerSplitableLayoutNodePtr ContainerNode = Node;
        ContainerNode->SetSubNodeSize(SubNodeIndex,Size);
    }
}

bool REditorSplitableLayoutViewModel::IsHorizontal(int64_t NodeIndex)
{
    auto Node = Model->Nodes[NodeIndex];
    if (Node->IsA<REditorContainerSplitableLayoutNode>())
    {
        REditorContainerSplitableLayoutNodePtr ContainerNode = Node;
        return ContainerNode->IsHorizontal();
    }
    return false;
}

void REditorSplitableLayoutViewModel::OnSpliterDragStarted(int64_t NodeIndex, int64_t SpliterIndex)
{
    DraggingSpliterIndex = SpliterIndex;
    DraggingSpliterNodeIndex = NodeIndex;
    auto Node = Model->Nodes[NodeIndex];
    assert(Node->IsA<REditorContainerSplitableLayoutNode>());
    REditorContainerSplitableLayoutNodePtr ContainerNode = Node;
    SubNodeSizesAtDraggingStart.Resize(ContainerNode->GetChildNum());
    for(int64_t i=0;i<ContainerNode->GetChildNum();i++)
    {
        SubNodeSizesAtDraggingStart[i]=ContainerNode->GetSubNodeSize(i);
    }
}

void REditorSplitableLayoutViewModel::OnSpliterDragMoved(int64_t NodeIndex, int64_t SpliterIndex, const SVec2 &Delta)
{
    auto Node = Model->Nodes[NodeIndex];
    assert(Node->IsA<REditorContainerSplitableLayoutNode>());
    REditorContainerSplitableLayoutNodePtr ContainerNode = Node;
    float DeltaSize = IsHorizontal(NodeIndex) ? Delta.X : Delta.Y;

    if(DeltaSize>0)
    {
        //向右/下拖动
        //1.先缩小右/下边的节点

        //真正缩小的值，可能比DeltaSize大(当自动隐藏的时候)
        //，也可能比DeltaSize小(当实在缩不下去的时候)
        float ShrinkSizeSum=0;
        for(int64_t i=SpliterIndex+1;i<ContainerNode->GetChildNum();i++)
        {
            if(ShrinkSizeSum>=DeltaSize)
            {
                //缩够了 不缩了
                break;
            }

            auto SubNodeSize = SubNodeSizesAtDraggingStart[i];
            if(SubNodeSize==0)
            {
                //这个节点已经是0了，没法再缩了
                continue;
            }

            //先尝试缩小到快速最小值
            auto QuickMinSize = ContainerNode->GetSubNodeQuickMinSize(i);
            if(SubNodeSize>QuickMinSize)
            {
                float ShrinkSize = std::min(SubNodeSize-QuickMinSize,DeltaSize-ShrinkSizeSum);
                assert(ShrinkSize>=0 && ShrinkSize<=SubNodeSize );
                SubNodeSize=SubNodeSize-ShrinkSize;
                ContainerNode->SetSubNodeSize(i,SubNodeSize);
                ShrinkSizeSum+=ShrinkSize;

                if(ShrinkSizeSum>=DeltaSize)
                {
                    //缩够了 不缩了
                    break;
                }
            }

            //此时节点大小=快速最小值
            auto MinSize=ContainerNode->GetSubNodeMinSize(i);
            if(SubNodeSize>MinSize)
            {
                //可以缩小到最小值
                ContainerNode->SetSubNodeSize(i,MinSize);
                ShrinkSizeSum+=SubNodeSize-MinSize;
                continue;
            }
        }

        //2.再扩大左/上边的节点
        ContainerNode->SetSubNodeSize(SpliterIndex,SubNodeSizesAtDraggingStart[SpliterIndex]+ShrinkSizeSum);
    }
    else if(DeltaSize<0)
    {
        //向左/上拖动
        //1.先缩小左/上边的节点

        //真正缩小的值，可能比DeltaSize大(当自动隐藏的时候)
        //，也可能比DeltaSize小(当实在缩不下去的时候)
        DeltaSize=-DeltaSize;
        float ShrinkSizeSum=0;
        for(int64_t i=SpliterIndex;i>=0;i--)
        {
            if(ShrinkSizeSum>=DeltaSize)
            {
                //缩够了 不缩了
                break;
            }

            auto SubNodeSize = SubNodeSizesAtDraggingStart[i];
            if(SubNodeSize==0)
            {
                //这个节点已经是0了，没法再缩了
                continue;
            }

            
            //先尝试缩小到快速最小值
            auto QuickMinSize = ContainerNode->GetSubNodeQuickMinSize(i);
            if(SubNodeSize>QuickMinSize)
            {
                float ShrinkSize = std::min(SubNodeSize-QuickMinSize,DeltaSize-ShrinkSizeSum);
                SubNodeSize=SubNodeSize-ShrinkSize;
                ContainerNode->SetSubNodeSize(i,SubNodeSize);
                ShrinkSizeSum+=ShrinkSize;

                if(ShrinkSizeSum>=DeltaSize)
                {
                    //缩够了 不缩了
                    break;
                }
            }

            auto MinSize= ContainerNode->GetSubNodeMinSize(i);
            if(SubNodeSize>MinSize)
            {
                //可以缩小到最小值
                ContainerNode->SetSubNodeSize(i,MinSize);
                ShrinkSizeSum+=SubNodeSize-MinSize;
                continue;
            }

        }

        //2.再扩大右/下边的节点
        ContainerNode->SetSubNodeSize(SpliterIndex+1,SubNodeSizesAtDraggingStart[SpliterIndex+1]+ShrinkSizeSum);
    }
    else
    {
        //直接应用大小
        for(int64_t i=0;i<ContainerNode->GetChildNum();i++)
        {
            ContainerNode->SetSubNodeSize(i,SubNodeSizesAtDraggingStart[i]);
        }
    }

}

void REditorSplitableLayoutViewModel::OnSpliterDragEnded(int64_t NodeIndex, int64_t SpliterIndex)
{
    DraggingSpliterIndex = -1;
    DraggingSpliterNodeIndex = -1;
    SubNodeSizesAtDraggingStart.Clear();
}

void REditorSplitableLayoutViewModel::OnEnterSpliter(int64_t NodeIndex, int64_t SpliterIndex)
{
    EnteredSpliterIndex = SpliterIndex;
    EnteredSpliterNodeIndex = NodeIndex;
}

void REditorSplitableLayoutViewModel::OnExitSpliter(int64_t NodeIndex, int64_t SpliterIndex)
{
    EnteredSpliterIndex = -1;
    EnteredSpliterNodeIndex = -1;
}

bool REditorSplitableLayoutViewModel::IsSpliterHighlighted(int64_t NodeIndex, int64_t SpliterIndex) const
{
    if(DraggingSpliterIndex==SpliterIndex && DraggingSpliterNodeIndex==NodeIndex)
    {
        //拖拽高亮
        return true;
    }

    //Hover高亮
    //TODO 增加延迟
    return EnteredSpliterIndex == SpliterIndex && EnteredSpliterNodeIndex == NodeIndex;
}

TSharedObjectPtr<RObject> REditorSplitableLayoutViewModel::GetItemViewModel(int64_t Index) const
{
    return ItemViewModels[Index];   
}
